"""
FinChat NLP 处理模块
负责用户输入的语义解析，包括意图识别和实体提取
使用 DeepSeek-R1 大模型进行自然语言理解
"""

import os
import json
import logging
from pydantic import BaseModel
from typing import Dict, Any
from app.services.deepseek import deepseek_client

# 设置日志
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger("nlp_processor")


class ParsedQuery(BaseModel):
    """解析后的查询结果模型"""
    intent: str  # 查询意图 (add_expense, query_expense, generate_report, etc.)
    entities: Dict[str, Any]  # 提取的实体 (money, category, date_range, etc.)


class NLPParser:
    """自然语言处理解析器"""

    def __init__(self, api_key: str = None):
        """
        初始化NLP解析器

        参数:
            api_key: DeepSeek API密钥，如果未提供则从环境变量获取
        """
        self.client = deepseek_client
        logger.info("NLP解析器初始化完成")

        # 如果提供了API密钥，覆盖默认配置
        if api_key:
            self.client.api_key = api_key
            logger.info("使用自定义API密钥")

    def parse_query(self, user_query: str) -> ParsedQuery:
        """
        解析用户查询，返回意图和实体

        参数:
            user_query: 用户输入的自然语言查询

        返回:
            ParsedQuery 对象，包含解析结果
        """
        logger.info(f"开始解析查询: '{user_query}'")

        # 构造系统提示词
        system_prompt = """
        作为财务助手，请解析以下用户查询：

        返回JSON格式:
        {
            "intent": "add_expense|query_expense|generate_report|financial_advice|...",
            "entities": {
                "money": 金额 (数值),
                "category": "类别名称",
                "date_range": "时间范围 (今天/本周/本月/上个月/自定义日期)",
                "merchant": "商家名称",
                "is_income": true/false (是否为收入),
                "note": "备注信息（仅当intent为add_expense时生效）",
                "report_type": "报告类型 (日报/周报/月报/自定义)"
            }
        }
        
        可用类别列表:
        相互转账, 早午晚餐, 交通, 零食水果, 房租房贷, 服饰鞋包, 家居百货, 
        礼金红包, 医疗用品, 护肤美容, 话费网费, 娱乐游玩, 其他, 零碎未记, 
        工资收入, 大额支出, 彤宝用品, 人情往来, 水电燃气

        注意:
        1. 当intent为"add_expense"时，"note"必须记录**花费用途和地点**，需排除时间和金额信息。
           - 例1: 用户输入"昨天午餐在星巴克花了35元" → note: "在星巴克吃午餐"
           - 例2: 用户输入"今天在永旺买了两件裙子，一双鞋子，花了2000" → note: "在永旺买了两件裙子，一双鞋子"
           - 例3: 用户输入"花了50元打车" → note: "打车"
        2. 只返回JSON格式结果，不要包含其他内容
        3. 如果金额未指定，设为null
        4. 如果无法识别的字段，设为''
        5. 时间范围格式: "YYYY-MM-DD" (自定义日期) 或预定义值
        """

        # 构造消息列表
        messages = [
            {"role": "system", "content": system_prompt},
            {"role": "user", "content": user_query}
        ]

        logger.debug("发送到DeepSeek的消息: %s", messages)

        try:
            # 调用DeepSeek API
            logger.info("调用DeepSeek API进行语义解析...")
            response = self.client.chat_completion(
                model="deepseek-chat",
                messages=messages,
                max_tokens=300,
                temperature=0.1  # 低温度确保稳定性
            )

            # 提取模型响应内容
            content = response['choices'][0]['message']['content']
            logger.debug("DeepSeek原始响应: %s", content)

            # 尝试解析JSON结果
            try:
                # 从响应中提取JSON部分（有时模型会添加额外文本）
                json_start = content.find('{')
                json_end = content.rfind('}') + 1
                json_str = content[json_start:json_end]

                # 解析JSON
                parsed_data = json.loads(json_str)
                logger.info("成功解析查询结果: %s", parsed_data)

                # 确保add_expense意图时note不为空（模型可能漏解析）
                if parsed_data.get('intent') == 'add_expense' and not parsed_data.get('entities', {}).get('note'):
                    # 调用备用note提取逻辑补充
                    parsed_data['entities']['note'] = user_query

                # 创建并返回ParsedQuery对象
                return ParsedQuery(
                    intent=parsed_data.get('intent', 'unknown'),
                    entities=parsed_data.get('entities', {})
                )

            except json.JSONDecodeError as e:
                logger.error("JSON解析失败: %s", e)
                logger.error("原始内容: %s", content)
                return self._fallback_parse(user_query)

        except Exception as e:
            logger.exception("DeepSeek API调用失败: %s", str(e))
            return self._fallback_parse(user_query)

    def _fallback_parse(self, user_query: str) -> ParsedQuery:
        """
        当主解析失败时的备用解析策略

        参数:
            user_query: 用户输入的自然语言查询

        返回:
            基本的ParsedQuery对象
        """
        logger.warning("使用备用解析策略处理查询: '%s'", user_query)

        # 简单的关键词匹配作为后备方案
        intent = "unknown"
        entities = {}

        # 检测添加支出/收入的关键词
        add_keywords = ["花了", "支付了", "收入", "收到", "添加"]
        if any(kw in user_query for kw in add_keywords):
            intent = "add_expense"

            # 简单提取金额
            for word in user_query.split():
                if word.replace('.', '', 1).isdigit():
                    entities['money'] = float(word)
                    break

        # 检测查询关键词
        query_keywords = ["多少", "查询", "查看", "统计"]
        if any(kw in user_query for kw in query_keywords):
            intent = "query_expense"

            # 检测时间范围
            time_keywords = {
                "今天": "today",
                "本周": "this_week",
                "本月": "this_month",
                "上个月": "last_month"
            }
            for kw, value in time_keywords.items():
                if kw in user_query:
                    entities['date_range'] = value
                    break

        logger.info("备用解析结果: intent=%s, entities=%s", intent, entities)
        return ParsedQuery(intent=intent, entities=entities)

    def debug_parse(self, user_query: str) -> Dict:
        """
        调试模式下的解析方法，返回完整的解析过程信息

        参数:
            user_query: 用户输入的自然语言查询

        返回:
            包含完整调试信息的字典
        """
        logger.info("调试模式解析: '%s'", user_query)

        # 构造系统提示词
        system_prompt = """
        作为财务助手，请解析以下用户查询：

        请详细解释你的思考过程，然后返回JSON格式结果:
        {
            "intent": "...",
            "entities": {...},
            "reasoning": "你的思考过程"
        }
        """

        # 构造消息列表
        messages = [
            {"role": "system", "content": system_prompt},
            {"role": "user", "content": user_query}
        ]

        # 调用DeepSeek API
        response = self.client.chat_completion(
            model="deepseek-chat",
            messages=messages,
            max_tokens=500,
            temperature=0.3
        )

        # 提取模型响应内容
        content = response['choices'][0]['message']['content']

        # 尝试解析JSON结果
        try:
            # 查找JSON部分
            json_start = content.find('{')
            json_end = content.rfind('}') + 1
            json_str = content[json_start:json_end]

            # 解析JSON
            return json.loads(json_str)
        except json.JSONDecodeError:
            # 如果无法解析，返回原始内容
            return {"raw_response": content}


# 测试函数
if __name__ == "__main__":
    # 设置详细日志
    logger.setLevel(logging.DEBUG)
    console_handler = logging.StreamHandler()
    console_handler.setLevel(logging.DEBUG)
    formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
    console_handler.setFormatter(formatter)
    logger.addHandler(console_handler)

    # 初始化解析器
    parser = NLPParser()

    # 测试查询
    test_queries = [
        "昨天午餐在星巴克花了35元",
        "本月餐饮支出总计多少",
        "给我生成上个月的消费报告",
        "我应该如何规划我的餐饮预算？",
        "这周在美团外卖花了多少钱"
    ]

    # 解析每个测试查询
    for i, query in enumerate(test_queries):
        print(f"\n{'=' * 50}")
        print(f"测试查询 {i + 1}: '{query}'")
        print(f"{'-' * 50}")

        # 解析查询
        result = parser.parse_query(query)

        # 打印结果
        print("解析结果:")
        print(f"  意图: {result.intent}")
        print("  实体:")
        for key, value in result.entities.items():
            print(f"    {key}: {value}")

        # 调试解析
        # debug_info = parser.debug_parse(query)
        # print("\n调试信息:")
        # print(json.dumps(debug_info, indent=2, ensure_ascii=False))